package application

import (
	"context"
	"forum/internal/common"
	"forum/internal/domain"
	"forum/internal/domain/event/article"
	"forum/internal/domain/repo"
	"forum/internal/domain/vo"
)

type ArticleService interface {
	Edit(ctx context.Context, uid int64, article domain.Article) (int64, error)
	Publish(ctx context.Context, id int64, article domain.Article) (int64, error)
	GetList(ctx context.Context, id int64, cursor vo.Page) ([]domain.Article, error)
	AuthorGetDetail(ctx context.Context, id int64, uid int64) (domain.Article, error)
	GetPubDetail(ctx context.Context, id int64, uid int64) (domain.Article, error)
}

type ArticleServiceImp struct {
	articleRepo repo.ArticleRepository
	userRepo    repo.UserRepository

	readProducer article.Producer
}

func NewArticleServiceImp(articleRepo repo.ArticleRepository, userRepo repo.UserRepository, readProducer article.Producer) *ArticleServiceImp {
	return &ArticleServiceImp{
		articleRepo:  articleRepo,
		userRepo:     userRepo,
		readProducer: readProducer,
	}
}

func (a *ArticleServiceImp) Edit(ctx context.Context, uid int64, article domain.Article) (int64, error) {
	article.Status = domain.ArticleStatusUnpublished
	if article.Id > 0 {
		err := a.articleRepo.Update(ctx, uid, article)
		return article.Id, err
	}
	return a.articleRepo.Save(ctx, uid, article)
}

func (a *ArticleServiceImp) Publish(ctx context.Context, id int64, article domain.Article) (int64, error) {
	article.Status = domain.ArticleStatusPublished
	return a.articleRepo.Sync(ctx, id, article)
}

func (a *ArticleServiceImp) GetList(ctx context.Context, id int64, cursor vo.Page) ([]domain.Article, error) {
	return a.articleRepo.GetAllByAuthorId(ctx, id, cursor)
}

func (a *ArticleServiceImp) AuthorGetDetail(ctx context.Context, id int64, uid int64) (domain.Article, error) {
	art, err := a.articleRepo.GetById(ctx, id)
	if err != nil {
		return art, err
	}
	if art.Author.Id != uid {
		return art, common.ErrNotAuthor
	}
	a.articleRepo.SyncCache(ctx, art)
	return art, err
}

func (a *ArticleServiceImp) GetPubDetail(ctx context.Context, id int64, uid int64) (domain.Article, error) {
	art, err := a.articleRepo.GetPubArticleById(ctx, id)
	if err != nil {
		return domain.Article{}, err
	}
	go func() {
		er := a.readProducer.ProduceReadEvent(article.ReadEvent{
			Aid: id,
			Uid: uid,
		})
		if er != nil {
			//TODO log
		}
	}()
	author, err := a.userRepo.FindById(ctx, art.Author.Id)
	art.Author.Name = author.Name
	return art, err
}
